package com.ybbase.framework.base.controller;


import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.ybbase.framework.base.model.ResponseBean;
import com.ybbase.framework.common.constant.CommonResultCode;
import com.ybbase.framework.common.constant.ConfigConstant;
import com.ybbase.framework.config.file.FileConfig;
import com.ybbase.framework.model.po.flow.NodeRecord;
import com.ybbase.framework.model.po.system.Annex;
import com.ybbase.framework.model.po.system.Organization;
import com.ybbase.framework.model.po.system.User;
import com.ybbase.framework.model.vo.flow.NodeRecordVO;
import com.ybbase.framework.service.system.AnnexService;
import com.ybbase.framework.service.system.OrganizationService;
import com.ybbase.framework.service.system.UserService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * BaseController
 *
 * @author cg
 * @date 2019-07-09 12:07
 * @since 4.0
 */
@RestController
@RequestMapping("/base")
public class BaseController {

    private static final Logger LOGGER = LogManager.getLogger(BaseController.class);

    private static final String JWT_USER_ID = "userId";
    private static final String JWT_USERNAME = "username";
    private static final String JWT_ORG_ID = "orgId";

    @Autowired
    UserService userService;
    @Autowired
    OrganizationService organizationService;
    @Autowired
    FileConfig fileConfig;
    @Resource
    private CacheManager cacheManager;
    @Autowired
    private AnnexService annexService;

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return java.lang.String
     * @author chengang
     * @date 2019/9/7 9:50 上午
     * @since 4.0
     */
    protected String getUsername(String token) {
        String username = "";
        try {
            DecodedJWT jwt = JWT.decode(token);
            username = jwt.getClaim(JWT_USERNAME).asString();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            LOGGER.error("BaseController-getUsername-根据token获取username异常:" + e.getMessage());
        }
        return username;
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @param token token
     * @return java.lang.String
     * @author chengang
     * @date 2019/9/7 9:51 上午
     * @since 4.0
     */
    protected String getUserId(String token) {
        String userId = "";
        try {
            DecodedJWT jwt = JWT.decode(token);
            userId = jwt.getClaim(JWT_USER_ID).asString();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            LOGGER.error("BaseController-getUserId-根据token获取userId异常:" + e.getMessage());
        }
        return userId;
    }

    /**
     * 根据token获取用户信息
     *
     * @param token token
     * @return User
     * @throws Exception 获取用户发生异常
     * @author chengang
     * @date 2019-08-06 09:22
     * @since 4.0
     */
    protected User getAtUser(String token) throws Exception {
        String userId = getUserId(token);
        User user = new User();
        if (StringUtils.isNotEmpty(userId)) {
            user = userService.getById(Integer.parseInt(userId));
        }
        return user;
    }

    /**
     * 根据token获取用户机构信息
     *
     * @param token token
     * @return Organization 用户的机构id与机构名称
     * @throws Exception 获取组织结构发生异常
     * @author yanBin
     * @date 2019-08-22 14:34
     * @since 4.0
     */
    protected Organization getOrganization(String token) throws Exception {
        Organization org = null;
        try {
            String id = getOrgId(token);
            if (StringUtils.isNotEmpty(id)) {
                org = organizationService.getById(Integer.parseInt(id));
            }
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            LOGGER.error("BaseController-getOrganization:根据token获取organization异常:" + e.getMessage());
        }
        return org;
    }

    /**
     * 根据token获取用户机构信息
     *
     * @param userId 用户编码
     * @return Organization 用户的机构id与机构名称
     * @throws Exception 获取组织结构发生异常
     * @author yanBin
     * @date 2019-08-22 14:34
     * @since 4.0
     */
    protected Organization getOrganizationByUserId(String userId) throws Exception {
        Organization org = null;
        try {
            List<Organization> organizationList = organizationService.getOrgListByUserId(Integer.parseInt(userId));
            if (organizationList != null && !organizationList.isEmpty()) {
                org = organizationList.get(0);
            }
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            LOGGER.error("BaseController-getOrganization:根据token获取organization异常:" + e.getMessage());
        }
        return org;
    }

    /**
     * 业务方法：根据token获取联社
     *
     * @param token
     * @return
     * @author cg
     * @date 2020-01-01 11:04
     * @since cloud2.0
     */
    public Organization getOrganLsByUserId(String token) {
        String orgId = getOrgId(token);
        Organization organization = organizationService.getById(Integer.parseInt(orgId));
        Organization lsOrgan = new Organization();
        String[] organIds = organization.getPath().split("[|]");
        if (organIds != null && organIds.length > 0) {
            List<Organization> list = organizationService.getOrgListQuery(organIds, 1);
            if (list != null && !list.isEmpty()) {
                lsOrgan = list.get(0);
            }
        }
        return lsOrgan;
    }

    /**
     * 业务方法：根据token获取支行
     *
     * @param token
     * @return
     * @author cg
     * @date 2020-01-01 11:04
     * @since cloud2.0
     */
    public Organization getOrganZhByUserId(String token) {
        String orgId = getOrgId(token);
        Organization organization = organizationService.getById(Integer.parseInt(orgId));
        Organization lsOrgan = new Organization();
        String[] organIds = organization.getPath().split("[|]");
        if (organIds != null && organIds.length > 1) {
            List<Organization> list = organizationService.getOrgListQuery(organIds, 2);
            if (list != null && !list.isEmpty()) {
                lsOrgan = list.get(0);
            }
        }
        return lsOrgan;
    }

    /**
     * 获取是否为管理员
     *
     * @param
     * @return
     * @author cg
     * @date 2020-01-01 18:04
     * @since cloud2.0
     */
    public Integer getIsAdmin(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("isAdmin").asInt();
    }

    /**
     * 获取下钻的组织机构列表
     *
     * @param
     * @return
     * @author cg
     * @date 2020-01-02 00:07
     * @since cloud2.0
     */
    public List<Organization> getDrillOrganList(String token) throws Exception {
        String orgId = getOrgId(token);
        Organization organization = organizationService.getById(Integer.parseInt(orgId));
        return organizationService.getOrgListByPath(organization.getPath());
    }

    /**
     * 获取下钻的组织机构数组
     *
     * @param
     * @return
     * @author cg
     * @date 2020-01-02 00:07
     * @since cloud2.0
     */
    public String[] getDrillOrganStr(String token) throws Exception {
        String orgId = getOrgId(token);
        Organization organization = organizationService.getById(Integer.parseInt(orgId));
        List<Organization> list = organizationService.getOrgListByPath(organization.getPath());
        String s = "";
        if (list != null && !list.isEmpty()) {
            for (Organization o : list) {
                s = s + o.getId() + ",";
            }
        }
        return s.split(",");
    }

    /**
     * 获取下钻的组织机构数组
     *
     * @param
     * @return
     * @author cg
     * @date 2020-01-02 00:07
     * @since cloud2.0
     */
    public String getDrillOrganString(String token) throws Exception {
        String orgId = getOrgId(token);
        Organization organization = organizationService.getById(Integer.parseInt(orgId));
        List<Organization> list = organizationService.getOrgListByPath(organization.getPath());
        String s = "";
        if (list != null && !list.isEmpty()) {
            for (Organization o : list) {
                s = s + o.getId() + ",";
            }
        }
        return s.lastIndexOf(",") != -1 ? s.substring(0, s.length() - 1) : s;
    }

    /**
     * 获取下钻的组织机构部门数组
     *
     * @param
     * @return
     * @author cg
     * @date 2020-01-02 00:07
     * @since cloud2.0
     */
    public String[] getDrillOrganDeprtStr(String token) throws Exception {
        String orgId = getOrgId(token);
        Organization organization = organizationService.getById(Integer.parseInt(orgId));
        List<Organization> list = organizationService.getOrgListByPath(organization.getPath());
        String s = "";
        if (list != null && !list.isEmpty()) {
            for (Organization o : list) {
                if (o.getType() == 3) {
                    s = s + o.getId() + ",";
                }
            }
        }
        return s.split(",");
    }

    /**
     * 根据token获取用户机构信息
     *
     * @param token token
     * @return org 用户的机构id与机构名称
     * @author yanBin
     * @date 2019-08-22 14:34
     * @since 4.0
     */
    protected String getOrgId(String token) {
        String orgId = "";
        try {
            DecodedJWT jwt = JWT.decode(token);
            orgId = jwt.getClaim(JWT_ORG_ID).asString();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            LOGGER.error("BaseController-getOrgId:根据token获取orgId异常:" + e.getMessage());
        }
        return orgId;
    }

    /**
     * 获取token串
     *
     * @param request HttpServletRequest对象
     * @return String token
     * @author yanbin
     * @date 2019/8/28 17:36
     * @since 4.0
     */
    protected String getTokenString(HttpServletRequest request) {
        return request.getHeader(ConfigConstant.HEADER_TOKEN_NAME);
    }


    /**
     * 根据登录人的组织机构获取他组织机构的代码，
     * 并且分析出对应的FlowCode
     *
     * @param request http请求
     * @return 流程编码
     * @throws Exception 异常
     * @author cg
     * @date 2019-09-11 17:19
     * @since 4.0
     */
    protected String getFlowCodeByToken(HttpServletRequest request) throws Exception {
        return getOrganization(getTokenString(request)).getFlowType();
    }

    /**
     * 查询向下的ID集合
     *
     * @param request http请求
     * @return listStr 向下的集合
     * @throws Exception 异常
     * @author cg
     * @date 2019-09-16 17:40
     * @since 4.0
     */
    protected String getToDownExtendOrgId(HttpServletRequest request) throws Exception {
        Organization organization = getOrganization(getTokenString(request));
        List<Organization> list = organizationService.getOrgListByPath(organization.getPath());
        String listStr = "";
        StringBuilder stringBuilder = new StringBuilder();
        if (list != null && list.size() > 0) {
            for (Organization organ : list) {
                stringBuilder.append(organ.getId() + ",");
            }
            listStr = StringUtils.isNotEmpty(stringBuilder.toString()) ?
                    stringBuilder.toString().substring(0, list.size() - 2) : "";
        }
        return listStr;
    }


    /**
     * 上传文件
     *
     * @param
     * @return
     * @author cg
     * @date 2019-12-15 18:18
     * @since cloud2.0
     */
    @RequestMapping(value = "/uploadSource", method = RequestMethod.POST)
    public void uploadSource(@RequestParam("file") MultipartFile file, HttpServletRequest request, HttpServletResponse httpResponse) {
        String pathString = null;
        if (file != null) {
            pathString = fileConfig.filePath + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "_" + file.getOriginalFilename();
        }
        try {
            File files = new File(pathString);
            //打印查看上传路径
            System.out.println(pathString);
            if (!files.getParentFile().exists()) {
                files.getParentFile().mkdirs();
            }
            file.transferTo(files);
            this.outStream(0, file.getOriginalFilename(), pathString, httpResponse);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            this.outStream(-1, "", "", httpResponse);
        }
    }

    /**
     *根据文件路径删除文件
     * @param
     * @return
     * @author cg
     * @date 2020-02-23 16:23
     * @since cloud2.0
     */
    @GetMapping("/removeFiles")
    public ResponseBean removeFiles(String path,HttpServletRequest request) {
        try {
            QueryWrapper<Annex> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(Annex::getPath, path);
            queryWrapper.lambda().eq(Annex::getCreateBy, getUserId(getTokenString(request)));
            annexService.remove(queryWrapper);
            /**
             * 读取
             * */
            File file = new File(path);
            /**
             * 判断是否是文件夹
             * */
            if (file.isFile()) {
                /**
                 * 删除
                 * */
                file.delete();
             }
             return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "删除"+CommonResultCode.SUCCESS.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseBean(CommonResultCode.FAIL.getCode(), "删除"+CommonResultCode.FAIL.getMsg());
        }
    }

    /**
     * 输出流
     *
     * @param code 错误代码
     * @return
     * @throws
     * @author cg
     * @date 2019-08-29 09:48
     * @since
     */
    public void outStream(Integer code, String name, String path, HttpServletResponse httpResponse) {
        httpResponse.setHeader("Content-type", ConfigConstant.CONTENT_TYPE_HTML);
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,HEAD,PUT,DELETE");
        httpResponse.setHeader("Access-Control-Allow-Headers", "*");
        OutputStream outputStream = null;
        try {
            outputStream = httpResponse.getOutputStream();
            byte[] JWT_CODE = ("{\"code\":" + code + ",\"name\":\"" + name + "\",\"path\":\"" + path + "\"}").getBytes(ConfigConstant.CHARACTER_ENCODING);
            outputStream.write(JWT_CODE);
            outputStream.close();
        } catch (IOException eio) {
            eio.printStackTrace();
        }
    }

    /**
     * 文件下载
     *
     * @param
     * @return
     * @author cg
     * @date 2019-12-22 18:29
     * @since cloud2.0
     */
    @RequestMapping("/downloadFile")
    public String downloadFile(@RequestParam String path, HttpServletResponse response) throws Exception{
        if (path != null) {
            path = URLDecoder.decode(URLDecoder.decode(path, "UTF-8"),"UTF-8");
            path= path.replace(" & #40;", " (").replace("& #41;", ")");
            File file = new File(path);
            if (file.exists()) {
                String[] ags =path.split("_");
                response.setContentType("application/octet-stream");
                response.setHeader("content-type", "application/octet-stream;charset=utf-8");
                response.setHeader("Content-Type", "text/html");
                response.addHeader("content-disposition", "attachment;filename="
                        +URLEncoder.encode(ags[ags.length-1],"UTF-8"));
                byte[] buffer = new byte[1024 * 100];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);
                    bis = new BufferedInputStream(fis);
                    OutputStream os = response.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1) {
                        os.write(buffer, 0, i);
                        i = bis.read(buffer);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 文件下载文件加名称
     *
     * @param
     * @return
     * @author cg
     * @date 2019-12-22 18:29
     * @since cloud2.0
     */
    public String downloadFile(@RequestParam String path, String fileName, HttpServletResponse response) {
        if (path != null) {
            File file = new File(path);
            if (file.exists()) {
                response.setContentType("application/octet-stream");
                response.setHeader("content-type", "application/octet-stream");
                response.setHeader("Content-Type", "text/html");
                response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
                byte[] buffer = new byte[1024 * 100];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);
                    bis = new BufferedInputStream(fis);
                    OutputStream os = response.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1) {
                        os.write(buffer, 0, i);
                        i = bis.read(buffer);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 根据节点记录拼装查询记录信息
     *
     * @param
     * @return
     * @author cg
     * @date 2019-12-22 22:22
     * @since cloud2.0
     */
    public List<NodeRecordVO> getNodeRecordVO(List<NodeRecord> list) {
        List<NodeRecordVO> nodeRecordVOList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                NodeRecordVO nodeRecordVO = new NodeRecordVO();
                nodeRecordVO.setSortNum(i + 1);
                String str = "";
                switch (list.get(i).getApprovalResult().split(":")[1]) {
                    case "0":
                        str = "，退回";
                        break;
                    case "1":
                        str = "，同意";
                        break;
                    case "-1":
                        str = "，撤回";
                        break;
                    case "-2":
                        str = "，直接结束";
                        break;
                    default:
                        break;
                }
                nodeRecordVO.setOperation(list.get(i).getNodeName() + str);
                nodeRecordVO.setOperatorName(list.get(i).getAssigneeName());
                nodeRecordVO.setOperatorDate(list.get(i).getEndTime());
                nodeRecordVO.setInstructions("null".equals(list.get(i).getAssigneeContent()) ? "" :
                        list.get(i).getAssigneeContent());
                nodeRecordVO.setNextNodeApproveNames(list.get(i).getNextNodeApproveNames());
                nodeRecordVO.setOrganName(list.get(i).getOrganName());
                nodeRecordVOList.add(nodeRecordVO);
            }
        }
        return nodeRecordVOList;
    }


    /**
     * 生成验证码图片
     *
     * @param request            设置session
     * @param response           转成图片
     * @param captchaProducer    生成图片方法类
     * @param validateSessionKey session名称
     * @throws Exception
     */

    public void validateCode(HttpServletRequest request, HttpServletResponse response, DefaultKaptcha captchaProducer, String validateSessionKey) throws Exception {
        // Set to expire far in the past.
        response.setDateHeader("Expires", 0);
        // Set standard HTTP/1.1 no-cache headers.
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // Set standard HTTP/1.0 no-cache header.
        response.setHeader("Pragma", "no-cache");

        // return a jpeg
        response.setContentType("image/jpeg");

        // create the text for the image
        String capText = captchaProducer.createText();

        // store the text in the session
        setValidateSessionKey(capText);

        // create the image with the text
        BufferedImage bi = captchaProducer.createImage(capText);

        ServletOutputStream out = response.getOutputStream();

        // write the data out
        ImageIO.write(bi, "jpg", out);
        try {
            out.flush();
        } finally {
            out.close();
        }
    }

    public void setValidateSessionKey(String capText) {
        Cache cache = cacheManager.getCache("validateCode");
        cache.put("capText", capText);
        System.out.println("缓存成功");
        String res = cache.get("capText", String.class);
        System.out.println(res);
    }

    public String getValidateSessionKey() {
        Cache cache = cacheManager.getCache("validateCode");
        String res = cache.get("capText", String.class);
        return res;
    }
}
